home *** CD-ROM | disk | FTP | other *** search
-
- /*
- File: LayoutLibrary.c
-
- Contains: Line Layout library routines.
-
- Written by: Dave Opstad, Eric Mader
-
- Copyright: ©1989-1995 by Apple Computer, Inc., all rights reserved.
-
- Change History (most recent first):
-
- <3> 6/23/95 DGO Reorganized and cleaned up, including adding comments for every
- routine.
- <2> 1/9/95 JD changed 'boolean' to 'Boolean'
- <1> 1/9/95 JD First checked in (for earlier history, see skia project file).
-
- */
-
- #include <Types.h>
- #include <Memory.h>
- #include <Resources.h>
- #include <ToolUtils.h>
-
- #include <GXGraphics.h>
- #include <GXMath.h>
- #include <GXTypes.h>
- #include <GXLayout.h>
- #include <GXFonts.h>
-
- #include "LayoutLibrary.h"
- #include "FontLibrary.h"
-
- /* -------------------------------------------------------------------------------------------- */
-
- /* CONSTANTS */
-
- enum
- {
- extraLineGap = ff(2),
- lineStartsCount = 50
- };
-
- /* -------------------------------------------------------------------------------------------- */
-
- /* INTERNAL PROTOTYPES */
-
- static short CountBytes(char *text);
- static long GetNextOffset(gxShape layout, long offset);
- static long GetPreviousOffset(gxShape layout, long offset);
- static char *GetTextPiecePtr(const void *text[], const short textRunLengths[], short offset);
- static void SetStyleNamedFont(gxStyle s, unsigned char *name);
-
- /* -------------------------------------------------------------------------------------------- */
-
- /* INTERNAL ROUTINES */
-
- /* CountBytes is used by NewParagraph. It finds the string length up to but not including
- the first CR or HT. */
-
- static short CountBytes(char *text)
- {
- short count = 0;
-
- while (*text != 13 && *text != 9)
- {
- text += 1;
- count += 1;
- }
-
- return count;
- } /* CountBytes */
-
- /* -------------------------------------------------------------------------------------------- */
-
- /* GetNextOffset returns the offset of the next character in the shape, taking into account
- 8-bit and 16-bit characters and ligatures. */
-
- static long GetNextOffset(gxShape layout, long offset)
- {
- gxLayoutOffsetState offsetState;
- static long offsetStateSizes[] = {1, 2, 1, 2, 0};
- unsigned short firstGlyph, secondGlyph;
-
- GXGetOffsetGlyphs(layout, offset, 0, &offsetState, &firstGlyph, &secondGlyph);
-
- return offset + offsetStateSizes[offsetState & ~gxOffsetInsideLigature];
- } /* GetNextOffset */
-
- /* -------------------------------------------------------------------------------------------- */
-
- /* GetPreviousOffset returns the offset of the prior character in the shape, taking into
- account 8-bit and 16-bit characters and ligatures. */
-
- static long GetPreviousOffset(gxShape layout, long offset)
- {
- gxLayoutOffsetState offsetState;
- static long offsetStateSizes[] = {1, 1, 2, 2, 0};
- unsigned short firstGlyph, secondGlyph;
-
- GXGetOffsetGlyphs(layout, offset, 0, &offsetState, &firstGlyph, &secondGlyph);
-
- return offset - offsetStateSizes[offsetState & ~gxOffsetInsideLigature];
- } /* GetPreviousOffset */
-
- /* -------------------------------------------------------------------------------------------- */
-
- /* GetTestPiecePtr returns a chunk of text from the (possibly disparate) individual text
- pieces. It is used by NewStyledParagraph. */
-
- static char *GetTextPiecePtr(const void *text[], const short textRunLengths[], short offset)
- {
- char **pPiece = (char **) text;
- short oCopy = offset, *runLength = (short *) textRunLengths;
-
- while (oCopy > *runLength)
- {
- oCopy -= *runLength++;
- pPiece += 1;
- }
-
- return *pPiece + oCopy;
- } /* GetTextPiecePtr */
-
- /* -------------------------------------------------------------------------------------------- */
-
- /* SetStyleNamedFont sets the specified gxStyle's font to that font with the specified
- full name. Note that name is a Pascal string. */
-
- static void SetStyleNamedFont(gxStyle s, unsigned char *name)
- {
- gxFont fontID = FindPNameFont(gxFullFontName, name);
-
- if (fontID != GXGetStyleFont(s))
- GXSetStyleFont(s, fontID);
- } /* SetStyleNamedFont */
-
- /* -------------------------------------------------------------------------------------------- */
-
- /* EXPORTED ROUTINES */
-
- /* DisposeParagraph disposes of the memory associated with a paragraph. While currently
- simple, it could be more involved if the paragraph itself retains more information. */
-
- void DisposeParagraph(ParagraphRecordHandle paraRec)
- {
- short i;
-
- for (i = 0; i < (**paraRec).nLayouts; i += 1)
- GXDisposeShape((**paraRec).layouts[i]);
-
- DisposeHandle((Handle) paraRec);
- } /* DisposeParagraph */
-
- /* -------------------------------------------------------------------------------------------- */
-
- /* GetLayoutBounds returns a gxShape corresponding to the bounds of the specified layout. It
- differs from GXGetShapeBounds in two respects: first, it returns a shape (rather than just
- a rectangle); and second, it takes both the layout's position and its mapping into account
- (GXGetShapeBounds only takes the layout's position into account). */
-
- gxShape GetLayoutBounds(gxShape layout)
- {
- gxMapping thisMapping;
- gxRectangle thisRect;
- gxShape rectShape;
-
- GXGetShapeBounds(layout, 0, &thisRect);
- rectShape = GXNewRectangle(&thisRect);
- GXMapShape(rectShape, GXGetTransformMapping(GXGetShapeTransform(layout), &thisMapping));
- return rectShape;
- } /* GetLayoutBounds */
-
- /* -------------------------------------------------------------------------------------------- */
-
- /* InitializeLayoutOptions sets the default values into a gxLayoutOptions structure. */
-
- void InitializeLayoutOptions(gxLayoutOptions *layoutOptions)
- {
- layoutOptions->width = 0;
- layoutOptions->flush = 0;
- layoutOptions->just = 0;
- layoutOptions->flags = 0;
- layoutOptions->baselineRec = NULL;
- } /* InitializeLayoutOptions */
-
- /* -------------------------------------------------------------------------------------------- */
-
- /* InitializeRunControls sets all the fields of the specified gxRunControls struct to
- values indicating default behavior. */
-
- void InitializeRunControls(gxRunControls *runControls)
- {
- runControls->flags = 0;
- runControls->beforeWithStreamShift = 0;
- runControls->afterWithStreamShift = 0;
- runControls->crossStreamShift = 0;
- runControls->imposedWidth = 0;
- runControls->track = 0;
- runControls->hangingInhibitFactor = 0;
- runControls->kerningInhibitFactor = 0;
- runControls->baselineType = gxRomanBaseline;
- runControls->decompositionAdjustmentFactor = 0;
- } /* InitializeRunControls */
-
- /* -------------------------------------------------------------------------------------------- */
-
- /* InitializeStyleRunOverrides initializes all the fields of the specified StyleRunOverrides
- struct to their default values. */
-
- void InitializeStyleRunOverrides(StyleRunOverrides *overrides)
- {
- overrides->priorityJustOverride = NULL;
- overrides->glyphJustOverrides = NULL;
- overrides->glyphJustOverridesCount = 0;
- overrides->glyphSubstitutions = NULL;
- overrides->glyphSubstitutionsCount = 0;
- overrides->kerningAdjustments = NULL;
- overrides->kerningAdjustmentsCount = 0;
- } /* InitializeStyleRunOverrides */
-
- /* -------------------------------------------------------------------------------------------- */
-
- /* NewLayoutStyle allocated and then initializes a gxStyle with the specified text-related
- attributes. */
-
- gxStyle NewLayoutStyle(char *gxFontName, Fixed textSize, gxTextAttribute attr,
- gxRunControls *runControls, gxRunFeature runFeatures[], long runFeaturesCount,
- StyleRunOverrides *overrides)
-
- {
- gxStyle newStyle = GXNewStyle();
-
- SetLayoutStyle(newStyle, gxFontName, textSize, attr, runControls, runFeatures,
- runFeaturesCount, overrides);
-
- return newStyle;
- } /* NewLayoutStyle */
-
- /* -------------------------------------------------------------------------------------------- */
-
- /* NewParagraph is the simplest of the paragraph creation functions. It assumes a single
- gxStyle for the whole paragraph, and does its own deduction about where the paragraph
- ends (namely at a hard stop, CR or HT). */
-
- ParagraphRecordHandle NewParagraph(char *text, gxStyle baseStyle, Fixed width, long justified,
- Fixed lineHeight, gxPoint *firstOrigin)
-
- {
- Boolean startIsStaked;
- char *pChar;
- Fixed currLineDelta, textSize;
- gxByteOffset lineStarts[lineStartsCount], newLineStart, nextStake, nls2, priorStake,
- thisLineStart;
- gxLayoutOptions options;
- gxShape bigLayout, thisLine;
- ParagraphRecordHandle paraHandle;
- short byteCount, i, nextLineIndex;
-
- byteCount = CountBytes(text); /* doesn't count the CR or HT!! */
- bigLayout = GXNewLayout(1, &byteCount, (const void **) &text, 1, &byteCount, &baseStyle,
- 0, NULL, NULL, NULL, firstOrigin);
-
- /* We next compute the line breaks and store the offsets that correspond to them in a
- temporary array. */
-
- thisLineStart = 0;
- nextLineIndex = 0;
- while (thisLineStart < byteCount && nextLineIndex < lineStartsCount - 1)
- {
- lineStarts[nextLineIndex++] = thisLineStart;
- newLineStart = GXGetLayoutBreakOffset(bigLayout, thisLineStart, width, 0, NULL,
- &startIsStaked, &priorStake, &nextStake);
- if (newLineStart == byteCount)
- break;
- /* Now backtrack to first prior space. */
- nls2 = newLineStart;
- pChar = text + newLineStart - 1;
- while (nls2 >= 0 && *pChar != ' ')
- {
- pChar -= 1;
- nls2 -= 1;
- }
- if (nls2 < 0)
- thisLineStart = newLineStart;
- else
- thisLineStart = nls2;
- }
-
- lineStarts[nextLineIndex] = byteCount;
-
- /* Allocate space for the ParagraphRecord. */
-
- paraHandle = (ParagraphRecordHandle) NewHandle((Size) (sizeof(ParagraphRecord) +
- nextLineIndex * sizeof(gxShape)));
- (**paraHandle).nLayouts = nextLineIndex;
-
- /* Now create the layouts and place them in the ParagraphRecord. */
-
- InitializeLayoutOptions(&options);
- options.width = width;
- if (justified)
- options.just = fract1;
- textSize = GXGetStyleTextSize(baseStyle);
- currLineDelta = 0;
-
- for (i = 0; i < nextLineIndex; i++)
- {
- if (i == nextLineIndex - 1)
- options.just = 0; /* don't justify the last line... */
- thisLine = GXNewLayoutFromRange(bigLayout, lineStarts[i], lineStarts[i+1], &options, NULL);
- if (currLineDelta)
- GXMoveShape(thisLine, 0, currLineDelta);
- (**paraHandle).layouts[i] = thisLine;
- currLineDelta += (lineHeight ? lineHeight : (textSize + extraLineGap));
- }
-
- (**paraHandle).totalHeight = currLineDelta;
-
- GXDisposeShape(bigLayout);
- return paraHandle;
- } /* NewParagraph */
-
- /* -------------------------------------------------------------------------------------------- */
-
- /* NewSingleLayout builds a layout shape with the specified text, and with the specified text-
- related attributes. It is basically a single call that replaces the sequence: allocate a
- style, set up the style, and call GXNewLayout to make the layout. */
-
- gxShape NewSingleLayout(char *text, char *gxFontName, Fixed textSize, gxLayoutOptions *options,
- gxPoint *position, gxTextAttribute attr, gxRunControls *runControls,
- gxRunFeature runFeatures[], long runFeaturesCount, StyleRunOverrides *overrides)
-
- {
- char *s = &text[0];
- gxShape newLayoutShape;
- gxStyle newLayoutStyle;
- short len;
-
- newLayoutStyle = NewLayoutStyle(gxFontName, textSize, attr, runControls, runFeatures,
- runFeaturesCount, overrides);
-
- for (len = 0; *s++ != 0; len += 1)
- ;
-
- newLayoutShape = GXNewLayout(1, &len, (const void **) &text, 1, &len, &newLayoutStyle,
- 0, NULL, NULL, options, position);
-
- GXDisposeStyle(newLayoutStyle);
-
- return newLayoutShape;
- } /* NewSingleLayout */
-
- /* -------------------------------------------------------------------------------------------- */
-
- /* NewStyledParagraph takes inputs similar to those taken by GXNewLayout, but instead of
- creating a single line, it creates a paragraph of lines. */
-
- ParagraphRecordHandle NewStyledParagraph(long textRunCount, const void *text[],
- const short textRunLengths[], long styleRunCount, const gxStyle styles[],
- const short styleRunLengths[], long levelRunCount, const short levels[],
- const short levelRunLengths[], long totalByteCount, const gxLayoutOptions *layoutOptions,
- Fixed lineHeight, const gxPoint *firstOrigin)
-
- {
- Boolean startIsStaked;
- gxByteOffset lineStarts[lineStartsCount], newLineStart, nextStake,
- nls2, priorStake, thisLineStart;
- char *pChar, *pSav;
- Fixed currLineDelta, lineAscent, lineDescent;
- gxLayoutOptions specialOptions;
- ParagraphRecordHandle paraHandle;
- gxShape bigLayout, thisLine;
- short i, nextLineIndex;
-
- specialOptions = *layoutOptions;
- specialOptions.just = specialOptions.flush = 0;
- specialOptions.width = 0;
-
- bigLayout = GXNewLayout(textRunCount, textRunLengths, text, styleRunCount, styleRunLengths,
- styles, levelRunCount, levelRunLengths, levels, &specialOptions, firstOrigin);
-
- /* We next compute the gxLine breaks and store the offsets that correspond to them in a
- temporary array. */
-
- thisLineStart = 0;
- nextLineIndex = 0;
- while (thisLineStart < totalByteCount && nextLineIndex < lineStartsCount - 1)
- {
- lineStarts[nextLineIndex++] = thisLineStart;
- newLineStart = GXGetLayoutBreakOffset(bigLayout, thisLineStart, layoutOptions->width, 0,
- NULL, &startIsStaked, &priorStake, &nextStake);
- if (newLineStart == totalByteCount)
- break;
- /* Now backtrack to first prior space. */
- nls2 = newLineStart;
- pSav = pChar = GetTextPiecePtr(text, textRunLengths, GetPreviousOffset(bigLayout,
- newLineStart));
- while (nls2 >= lineStarts[nextLineIndex-1] && *pChar != ' ')
- pChar = GetTextPiecePtr(text, textRunLengths, nls2 = GetPreviousOffset(bigLayout, nls2));
-
- if (nls2 <= lineStarts[nextLineIndex-1])
- thisLineStart = newLineStart;
- else
- {
- if (pSav != pChar)
- nls2 = GetNextOffset(bigLayout, nls2);
- thisLineStart = nls2;
- }
- }
- lineStarts[nextLineIndex] = (short) totalByteCount;
-
- /* Allocate space for the ParagraphRecord. */
-
- paraHandle = (ParagraphRecordHandle) NewHandle((Size) (sizeof(ParagraphRecord) +
- nextLineIndex * sizeof(gxShape)));
- (**paraHandle).nLayouts = nextLineIndex;
-
- /* Now create the layouts and place them in the ParagraphRecord. */
-
- specialOptions = *layoutOptions;
- currLineDelta = 0;
-
- for (i = 0; i < nextLineIndex; i++)
- {
- if (i == nextLineIndex - 1)
- specialOptions.just = 0; /* don't justify last line... */
- thisLine = GXNewLayoutFromRange(bigLayout, lineStarts[i], lineStarts[i+1],
- &specialOptions, NULL);
- if (currLineDelta)
- GXMoveShape(thisLine, 0, currLineDelta);
- (**paraHandle).layouts[i] = thisLine;
- if (lineHeight)
- currLineDelta += lineHeight;
- else
- {
- GXGetLayoutSpan(thisLine, &lineAscent, &lineDescent);
- currLineDelta += lineAscent + lineDescent + extraLineGap;
- }
- }
-
- (**paraHandle).totalHeight = currLineDelta;
-
- GXDisposeShape(bigLayout);
- return paraHandle;
- } /* NewStyledParagraph */
-
- /* -------------------------------------------------------------------------------------------- */
-
- /* SetDefaultPriorityJustOverride initializes the fields of all the priorities in the specified
- gxPriorityJustificationOverride struct to zero. */
-
- void SetDefaultPriorityJustOverride(gxPriorityJustificationOverride *override)
- {
- gxWidthDeltaRecord *pDelta = override->deltas;
- short i;
-
- for (i = 0; i < gxNumberOfJustificationPriorities; i += 1)
- {
- pDelta->growFlags = 0;
- pDelta->shrinkFlags = 0;
- pDelta->beforeGrowLimit = 0;
- pDelta->afterGrowLimit = 0;
- pDelta->beforeShrinkLimit = 0;
- (pDelta++)->afterShrinkLimit = 0;
- } /* endloop i */
- } /* SetDefaultPriorityJustOverride */
-
- /* -------------------------------------------------------------------------------------------- */
-
- /* SetLayoutStyle is a fast way of setting up an existing gxStyle with lots of text-related
- attributes. If you want to allocate a new gxStyle and initialize it at the same time, see
- the NewLayoutStyle routine. */
-
- void SetLayoutStyle(gxStyle s, char *gxFontName, Fixed textSize, gxTextAttribute attr,
- gxRunControls *runControls, gxRunFeature runFeatures[], long runFeaturesCount,
- StyleRunOverrides *overrides)
-
- {
- gxRunControls localControls;
-
- #ifdef debugging
- GXIgnoreGraphicsNotice(attributes_already_set);
- GXIgnoreGraphicsNotice(text_attributes_already_set);
- #endif
-
- SetStyleNamedFont(s, (unsigned char *) gxFontName);
- GXSetStyleTextSize(s, textSize);
- GXSetStyleTextAttributes(s, attr);
-
- if (runControls == NULL)
- {
- InitializeRunControls(&localControls);
- runControls = &localControls;
- }
-
- GXSetStyleRunControls(s, runControls);
-
- if (runFeatures != NULL)
- GXSetStyleRunFeatures(s, runFeaturesCount, runFeatures);
-
- if (overrides != NULL)
- {
- if (overrides->glyphSubstitutions != NULL)
- GXSetStyleRunGlyphSubstitutions(s, overrides->glyphSubstitutionsCount, overrides->glyphSubstitutions);
- if (overrides->kerningAdjustments != NULL)
- GXSetStyleRunKerningAdjustments(s, overrides->kerningAdjustmentsCount, overrides->kerningAdjustments);
- if (overrides->glyphJustOverrides != NULL)
- GXSetStyleRunGlyphJustOverrides(s, overrides->glyphJustOverridesCount, overrides->glyphJustOverrides);
- if (overrides->priorityJustOverride != NULL)
- GXSetStyleRunPriorityJustOverride(s, overrides->priorityJustOverride);
- }
-
- #ifdef debugging
- GXPopGraphicsNotice();
- GXPopGraphicsNotice();
- #endif
-
- } /* SetLayoutStyle */
-